-- AwakeM
-- Create by chendh
-- 觉醒模块

module("AwakeM", package.seeall);

-- 所有的觉醒配置信息
local awakeTable = {};

local AWAKE_GUIDE_MAX       = 5;
local ATTRIB_PATH           = "slime_awake";
local SERVER_STATUS_RULE    = "slime_awake";
-- 升阶状态
CARVING_STATE_PREPARE     = 1;
CARVING_STATE_UPGRADING   = 2;
CARVING_STATE_FINISH      = 3;

-- 载入配置表
local _init = false;
local loadCsv = function()
    if _init then return end
    _init = true;

    -- 转换下信息表
    local awake_CSV = get_pet_awake_CSV();
    for i = 1, #awake_CSV do
        awakeTable[awake_CSV[i].class_id] = awake_CSV[i];
    end

    awake_CSV = {};
end

-- 模块初始化
function init()
    loadCsv();
end

-- 检索觉醒信息
function query(id, path)
    local m = awakeTable[id]

    if not m or path == "" or not path then
        return m
    end

    return m[path]
end

-- 获取所有已开放觉醒的冈布奥
function getAllOpenedAwake()
    -- 获取下觉醒开放数据
    local buff = ServerStatusM.query(SERVER_STATUS_RULE);

    if type(buff) ~= "string" then
        return {};
    end

    local data = BuffDataM.parseBufferData(buff, 1);
    local result = {};

    for petId, ret in ipairs(data) do
        if ret >= 1 then
            table.insert(result, petId);
        end
    end

    return result;
end

-- 判断是否开放了觉醒
function isAwakeOpened(petId)
    -- 获取下开关
    local buff = ServerStatusM.query(SERVER_STATUS_RULE);

    if type(buff) ~= "string" then
        return false;
    end

    local ret = BuffDataM.queryByData(buff, petId, 1);

    return ret >= 1;
end

-- 获取指引进度
function getGuideProgress()
    return ME.user.dbase:query("awake_guide") or 0;
end

-- 设置指引进度
function setGuideProgress(progress)
    local cur_progress = getGuideProgress();

    if cur_progress >= progress then
        return false;
    end

    -- 如果还未开放此进度
    if progress > AWAKE_GUIDE_MAX then
        doAlert(getLocStr("unopen_function_tip"));
        return false;
    end

    if progress == 5 then
        BonusM.doBonus({3, 125, 1}, "awake_guide");
    end

    ME.user.dbase:set("awake_guide", progress);

    Operation.cmd_set_awake_guide_progress(progress);
end

-- 是否结束了指引
function isFinishGuide()
    return getGuideProgress() >= AWAKE_GUIDE_MAX;
end

-- 获取冈布奥觉醒信息
function getAwakeInfo(petId)
    local info = ME.user.dbase:query(ATTRIB_PATH, {});

    if type(petId) == "number" then
        return info[petId];
    else
        return info;
    end
end

-- 是在觉醒副本中
function isInAwake()
    if not DungeonM.isInDungeon() then
        return false;
    end

    local dungeonId = DungeonM.getDungeonId();
    if not isAwakeDungeon(dungeonId) then
        return false;
    end

    return true;
end

-- 判断冈布奥是否完成了觉醒的地牢试炼
function isFinishAwakeDungeon(petId)
    local info = ME.user.dbase:query(ATTRIB_PATH, {});
    if not info[petId] then
        return false;
    else
        return info[petId]["dungeon_status"] >= 1;
    end
end

-- 判断冈布奥是否可以进行地牢试炼
function canAwakeDungeonTrial(petId)
    local pet = PetM.getMyPet(petId);

    -- 必须有这头冈布奥
    if not pet then
        return "no_pet";
    end

    -- 必须达到五星且装备了证书
    if pet:getRank() < 5 then
        return "rank_limit";
    end

    -- 必须装备了证书
    local hasMedal = EquipM.getHeroEquip(pet, EQUIP_TYPE_MEDAL, 1);
    if not hasMedal then
        return "not_medal";
    end

    -- 必须没完成过地牢试炼
    local info = ME.user.dbase:query(ATTRIB_PATH, {});
    if type(info[petId]) == "table" and info[petId]["dungeon_status"] >= 1 then
        return "finished";
    end

    return true;
end

-- 判断是否有任意冈布奥可以进行地牢试炼
function anyoneSlimeCanAwakeDungeon()
    local allPets = ME.user:getAllPets();
    for petId, _ in pairs(allPets) do
        if canAwakeDungeonTrial(petId) == true then
            return true;
        end
    end

    return false;
end

-- 判断是否有任意冈布奥可以进行雕像雕刻
function anyoneSlimeCanCarving()
    local allPets = ME.user:getAllPets();
    for petId, _ in pairs(allPets) do
        if AwakeM.isFinishAwakeDungeon(petId) and
            not AwakeM.isCarved(petId) then
            return true;
        end
    end

    return false;
end

-- 判断是否有任意宝珠可以进行熔炼
function anyonePearlCanCompound()
    local allPets = ME.user:getAllPets();
    for petId, _ in pairs(allPets) do
        local itemId = PetM.query(petId, "pearl");
        if AwakeM.canSmeltPearl(petId) == true and
            CompoundM.canDoCompound(CompoundM.getCompoundRule(itemId)) == true then
            return true;
        end
    end

    return false;
end

-- 计算已完成试炼地牢的冈布奥数量
function calcFinishedAwakeDungeonNum()
    local num = 0;
    local data = ME.user.dbase:query(ATTRIB_PATH, {});

    for _, info in pairs(data) do
        if info["dungeon_status"] >= 1 then
            num = num + 1;
        end
    end

    return num;
end

-- 计算招募雕刻家冈布奥要求多少冈布奥通关试炼
function recruitPetNumLimit()
    return 5;
end

-- 计算招募雕刻家冈布奥要求消耗多少金币
function recruitSculptorCostMoney()
    return 500000;
end

-- 判断是否可以熔炼指定冈布奥的宝珠
function canSmeltPearl(petId)
    local pet = PetM.getMyPet(petId);

    -- 必须有这头冈布奥
    if not pet then
        return "no_pet";
    end

    -- 必须达到五星且装备了证书
    if pet:getRank() < 5 then
        return "rank_limit";
    end

    -- 必须装备了证书
    local hasMedal = EquipM.getHeroEquip(pet, EQUIP_TYPE_MEDAL, 1);
    if not hasMedal then
        return "not_medal";
    end

    return true;
end

-- 计算熔炼宝珠需要消耗的碎片数量
function calcSmeltCostChipNum(petId)
    return 30;
end

-- 判断是否已建造雕像
function isCarved(classId)
    local data = ME.user.dbase:query(ATTRIB_PATH, {});
    if data[classId] and data[classId]["carved"] == 1 then
        return true;
    end

    return false;
end

-- 计算已经建造雕像的冈布奥数量
function calcCarvedNum()
    local num = 0;
    local petList = ME.user:getAllPets();
    for _, pet in ipairs(petList) do
        local petId = pet.classId;
        if isCarved(petId) then
            num = num + 1;
        end
    end

    return num;
end

-- 判断是否可以建造雕像
function canCarving(classId)
    local pet = PetM.getMyPet(classId);

    if not pet then
        return "no_pet";
    end

    if PetM.isActivePet(classId) then
        return "awake_actived_pet";
    end

    local lictors = LictorM.getLictorPets();
    for _, c in pairs(lictors) do
        -- 必须跟出战宠物同阵营
        if c == classId and DungeonM.isInDungeon() and DungeonM.isPause() then
            return "awake_lictor_pet";
        end
    end

    if isCarved(classId) then
        return "is_carved";
    end

    if pet:getRank() < 5 then
        return "awake_lack_rank";
    end

    local medalClassId = EquipM.getHeroEquip(pet, EQUIP_TYPE_MEDAL, 1);
    if medalClassId == nil then
        return "awake_lack_medal";
    end

    if not isFinishAwakeDungeon(classId) then
        return "awake_lack_dungeon";
    end

    return true;
end

-- 建造雕像的材料是否足够
function materialEnough(classId)
    -- 宝珠消耗
    local pearlCost = AwakeM.query(classId, "carving_cost");
    -- 晶核消耗
    local crystalCost = AwakeM.query(classId, "crystal_cost");

    for _, info in ipairs(table.append(pearlCost, crystalCost)) do
        local classId = info[2];
        local num = info[3];

        if ItemM.getAmount(ME.user, classId) < num then
            return false;
        end
    end

    return true;
end

-- 获取雕像雕刻信息
function getCarvingInfo()
    return ME.user.dbase:query("carving_room", {});
end

-- 获取雕像位上的英雄ID
function getCarvingHeroId()
    local info = getCarvingInfo();
    if info == nil or info.cur_hero == nil then
        return 0;
    end

    return info.cur_hero;
end

-- 获取雕像完成时间
function getCarvingFinishTime()
    local info = getCarvingInfo();
    if info == nil or info.finish_time == nil then
        return -1;
    end

    return info.finish_time;
end

-- 设置雕刻结束
function setCarvingEnd()
    local info = getCarvingInfo();
    info.cur_hero = 0;
    info.finish_time = nil;
end

-- 是否正在雕刻
function isCarving(classId)
    if getCarvingHeroId() == classId and getCarvingState() ~= CARVING_STATE_PREPARE then
        return true;
    end

    return false;
end

-- 获取当前英雄升阶状态
function getCarvingState()
    -- 获取完成时间
    local finishTime = getCarvingFinishTime();
    -- 服务器当前时间
    local serverTime = TimeM.getServerTime();

    if finishTime < 0 then
        return CARVING_STATE_PREPARE;
    elseif finishTime == 0 or serverTime >= finishTime then
        return CARVING_STATE_FINISH;
    else
        return CARVING_STATE_UPGRADING;
    end
end

-- 开始雕刻
function starCarving(classId)
    local pet = PetM.getMyPet(classId);
    local costTime = FormulaM.invoke("CALC_AWAKE_CARVING_COST_TIME");

    -- 扣除消耗
    local cost = table.append(query(classId, "carving_cost"), query(classId, "crystal_cost"));
    for _, arr in pairs(cost) do
        if arr[1] == 1 then
            ItemM.costAmount(ME.user, arr[2], arr[3]);
        elseif arr[1] == 2 then
            ME.user:costAttrib(arr[2], arr[3]);
        end
    end

    -- 服务器当前时间
    local serverTime = TimeM.getServerTime();
    local info = getCarvingInfo();
    info.cur_hero = classId;
    info.finish_time = serverTime + costTime;

    -- 去服务端执行开始雕刻
    Operation.cmd_awake_carving_start(classId);

    EventMgr.fire(event.AWAKE_CARVING_START, {["class_id"] = classId});
end

-- 加速雕刻
function boostCarving(classId)
    -- 加速升阶
    Operation.cmd_awake_carving_boost(classId);

    EventMgr.fire(event.AWAKE_CARVING_BOOST, {["class_id"] = classId});
end

-- 结束雕刻
function finishCarving(classId, prop)
    setCarvingEnd();

    -- 属性变化
    local info = ME.user.dbase:query(ATTRIB_PATH, {});
    info[classId]["carved"] = 1;
    info[classId]["prop"] = prop;

    -- 刷新属性
    local pet = PetM.getMyPet(classId);
    PropM.refresh(pet);

    EventMgr.fire(event.AWAKE_CARVING_FINISH, {["class_id"] = classId, ["prop"] = prop, });
end

-- 获取觉醒雕像带来的属性效果
function fetchAwakeCarvingProps(pet)
    local result = {};
    local classId = pet:query("classId");
    if not isCarved(classId) then
        return result;
    end

    -- 则先获取配置的雕像固定附加属性
    result = table.copy(query(classId, "prop") or {});

    -- 加上雕像额外附加的不固定属性
    local data = ME.user.dbase:query(ATTRIB_PATH, {});
    if type(data[classId]) == "table" and
        type(data[classId]["prop"]) == "table" then
        result = table.append(result, data[classId]["prop"]);
    end

    return result;
end

-- 获取觉醒雕像带来的属性效果描述
function fetchAwakeCarvingPropsDesc(classId, compact)
    local normalPropDesc = "";
    local speciallPropDesc = "";
    local prop = {};

    -- 天赋等级+1
    desc = getLocStr("talent_skill_level") .. "+1";

    -- 如果不要求紧凑显示，则换行一下，否则加个逗号
    if not compact then
        desc = desc .. "\n";
    else
        desc = desc .. getLocStr("comma");
    end

    -- 雕像固定属性描述
    prop = table.copy(query(classId, "prop") or {});
    normalPropDesc = desc .. EquipM.getEquipPropDesc(prop);

    -- 加上雕像额外附加的不固定属性
    local data = ME.user.dbase:query(ATTRIB_PATH, {});
    if type(data[classId]) == "table" and
        type(data[classId]["prop"]) == "table" then
        speciallPropDesc = EquipM.getEquipPropDesc(data[classId]["prop"]);
    else
        speciallPropDesc = getLocStr("awake_carving_extra_prop_desc");
    end

    return {normalPropDesc, speciallPropDesc};
end

-- 冈布奥雕像的属性是否达到最大值
function awakeCarvingPropIsMaxNum(classId)
    local awakeInfo = ME.user.dbase:query(ATTRIB_PATH, {});
    local info = awakeInfo[classId] or {};
    local prop = info["prop"];

    if not prop then
        return false;
    end

    -- 大于等于5则认为是最大值
    if prop[1][3] >= 5 then
        return true;
    else
        return false;
    end
end

-- 判断是否是冈布奥觉醒试炼界面
function isAwakeDungeon(dungeonId)
    if DungeonAreaM.query(dungeonId, "type") == "awake" then
        return true;
    end

    return false;
end

-- 觉醒系统是否开启
function isAwakeSystemOpen()
    local isOpen = ServerStatusM.query(MODULE_SWITCH_AWAKE);
    if not isOpen then
        return false;
    end

    return iif(isOpen == 1, true, false);
end
